﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Leow.SelectableCanvas
{
    public class AutoResizingCanvas : Canvas
    {
        private List<FrameworkElement> _children;
        private ItemsControl _itemsControl;
        private ScrollViewer _scrollViewer;

        public AutoResizingCanvas()
        {
            Loaded += LoadedEventHandler;
        }

        protected override Size ArrangeOverride(Size arrangeSize)
        {
            if (_scrollViewer != null && InternalChildren.Count != 0)
            {
                double minLeft = _children
                    .Min(elem => GetLeft(elem));
                double minTop = _children
                    .Min(elem => GetTop(elem));

                minLeft = Math.Min(0, minLeft);
                minTop = Math.Min(0, minTop);

                _children.ForEach(
                    c => c.RenderTransform = new TranslateTransform(-minLeft, -minTop));

                double maxWidth = -minLeft + _children
                    .Max(elem => GetLeft(elem) + elem.ActualWidth);
                double maxHeight = -minTop + _children
                    .Max(elem => GetTop(elem) + elem.ActualHeight);

                double visibleWidth
                    = _scrollViewer.ViewportWidth - Margin.Left - Margin.Right;
                double visibleHeight
                    = _scrollViewer.ViewportHeight - Margin.Top - Margin.Bottom;

                if (_itemsControl != null)
                {
                    visibleWidth -=
                        _itemsControl.Margin.Left + _itemsControl.Margin.Right
                        + _itemsControl.Padding.Left + _itemsControl.Padding.Right;
                    visibleHeight -=
                        _itemsControl.Margin.Top + _itemsControl.Margin.Bottom
                        + _itemsControl.Padding.Top + _itemsControl.Padding.Bottom;
                }

                Width = maxWidth > visibleWidth ? maxWidth : double.NaN;
                Height = maxHeight > visibleHeight ? maxHeight : double.NaN;
            }

            return base.ArrangeOverride(arrangeSize);
        }

        protected override void OnVisualChildrenChanged(
            DependencyObject visualAdded,
            DependencyObject visualRemoved)
        {
            base.OnVisualChildrenChanged(visualAdded, visualRemoved);

            _children = InternalChildren
                .Cast<FrameworkElement>()
                .ToList();
        }

        private void LoadedEventHandler(object sender, RoutedEventArgs e)
        {
            _scrollViewer = this
                .GetFirstVisualParentOfType<ScrollViewer>();
            _itemsControl = ItemsControl.GetItemsOwner(this);

            InvalidateArrange();
        }
    }
}
